package net.wangds.poi.utils;

import net.wangds.utils.DateUtils;
import net.wangds.utils.FileUtils;
import net.wangds.spring.utils.SpringUtils;
import net.wangds.log.helper.LogHelper;
import net.wangds.poi.comp.AbstractExcelComp;
import net.wangds.poi.excel2003.comp.Excel2003Comp;
import net.wangds.poi.excel2007.comp.Excel2007Comp;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.*;
import org.springframework.core.io.Resource;

import java.util.Date;
import java.util.function.BiConsumer;
import java.util.function.Consumer;

public class ExcelUtils {

    /**
     * 获得Excel处理组件.
     * @param version 版本.
     *                <ul>
     *                <li>2003;/li>
     *                <li>2007 or other.</li>
     *                </ul>
     * @return
     */
    public static AbstractExcelComp fetchExcelComp(String version){
        switch(version){
            case "2003":
                return SpringUtils.getBean(Excel2003Comp.class);
            default:
                return SpringUtils.getBean(Excel2007Comp.class);
        }
    }

    public static void processExcel(Resource rsc, Consumer<Workbook> onSuccess, Consumer<Exception> onException){
        String fileName = rsc.getFilename();
        String suffix = StringUtils.lowerCase(FileUtils.suffixNoDot(fileName));
        AbstractExcelComp cmp;
        switch(suffix){
            case "xls":
                cmp = fetchExcelComp("2003");
                break;
            case "xlsx":
                cmp = fetchExcelComp("2007");
                break;
            default:
                throw new RuntimeException("无法根据后缀名确定Excel文件格式:"+rsc.getFilename()+","+suffix);
        }
        if(cmp!=null){
            cmp.onWorkbook(rsc, onSuccess, onException);
        }
    }

    public static void processSheet(Resource rsc, int sheetIdxB0, Consumer<Sheet> onSuccess, Consumer<Exception> onException){
        processExcel(rsc, (wb)->{
            if(onSuccess!=null){
                onSuccess.accept(wb.getSheetAt(sheetIdxB0));
            }
        }, onException);
    }

    public static void processRows(Resource rsc, int sheetIdxB0, BiConsumer<Row, Integer> onSuccess, BiConsumer<Exception, Integer> onRowException, Consumer<Exception> onException){
        processExcel(rsc, (wb)->{
            processRows(wb, sheetIdxB0, onSuccess, onRowException);
        }, onException);
    }

    public static void processRows(Workbook wb, int sheetIdxB0, BiConsumer<Row, Integer> onSuccess, BiConsumer<Exception, Integer> onException){
            if(onSuccess!=null){
                Sheet sheet = wb.getSheetAt(sheetIdxB0);
                if(sheet!=null){
                    int max = sheet.getLastRowNum();
                    for(int i=0;i<=max;i++){
                        try {
                            onSuccess.accept(sheet.getRow(i), i);
                        }catch(Exception e){
                            if(onException!=null){
                                onException.accept(e, i);
                            }
                        }
                    }
                }
            }
    }

    public static void readCellValue(Cell cell,
                                Consumer<String> onString,
                                Consumer<Double> onNumber,
                                Consumer<Date> onDate,
                                Consumer<Boolean> onBoolean,
                                BiConsumer<Cell,String> onFormula,
                                Runnable onBlank,
                                Runnable onNone,
                                Consumer<Byte> onError){
        if(cell!=null){
            switch(cell.getCellType()){
                case NUMERIC:
                    if(DateUtil.isCellDateFormatted(cell)){
                        if(onDate!=null){
                            onDate.accept(cell.getDateCellValue());
                        }
                    }else{
                        if(onNumber!=null){
                            onNumber.accept(cell.getNumericCellValue());
                        }
                    }
                    break;
                case FORMULA:
                    if(onFormula!=null) {
                        onFormula.accept(cell, cell.getCellFormula());
                    }
                    break;
                case BOOLEAN:
                    if(onBoolean!=null){
                        onBoolean.accept(cell.getBooleanCellValue());
                    }
                    break;
                case STRING:
                    if(onString!=null){
                        onString.accept(cell.getStringCellValue());
                    }
                    break;
                case BLANK:
                    if(onBlank!=null){
                        onBlank.run();
                    }
                    break;
                case ERROR:
                    if(onError!=null){
                        onError.accept(cell.getErrorCellValue());
                    }
                    break;
                case _NONE:
                    default:
                    if(onNone!=null){
                        onNone.run();
                    }
                    break;
            }
        }


    }

    public static void readCellAsStringValue(Cell cell, Consumer<String> onString){
        readCellValue(cell, onString, (db)->onString.accept(Double.toString(db)),
                (dt)->onString.accept(DateUtils.toDefaultDateStr(dt)),
                (bl)->onString.accept(Boolean.toString(bl)),
                (c,formula)->onString.accept(formula),
                ()->onString.accept(""),
                ()->onString.accept(null),
                (error)->{LogHelper.error(()->"读取单元格"+cell.getRowIndex()+","+cell.getColumnIndex()
                        +"时发生错误，错误代码为："+error);}
                );
    }

}
